home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / fortune-.tar / fortune- / fortune / util / ansify.c next >
C/C++ Source or Header  |  1995-10-12  |  11KB  |  366 lines

  1. /*
  2.  * ansify.c v. 0.1.0 Oct. 3, 1995
  3.  * 
  4.  * A trivial little program.  It checks a text file for ctl-H characters
  5.  * (like col, for instance), and where it finds them, tries to figure out
  6.  * if it's underlining or double-striking (bolding) or an attempt to display
  7.  * a special character.
  8.  * 
  9.  * If the file contains any of that, the program modifies the string in
  10.  * memory to turn on VT100 control sequences governing underline and 
  11.  * bold.  v. 0.2.0 will add a configuration file which can override 
  12.  * VT100 sequences with locally-specified control codes.  v 0.3.0 will add
  13.  * to the configuration file specification of control codes for non-ASCII
  14.  * characters (accented characters, primarily).
  15.  *
  16.  * The reason for writing this is so silly text files like the databases
  17.  * for the fortune program can have 'real' bold and underline on VT100
  18.  * compliant screens (which means most terminals, I think).
  19.  * 
  20.  * Usage: ansify [-x] [-c _config-file_] _input-file_ [_output-file_]
  21.  * 
  22.  *                   -x : remove backspaces, like col(1)
  23.  *     -c _config-file_ : Read _config-file_ for control codes
  24.  *         _input-file_ : File to examine for ^H sequences
  25.  *        _output-file_ : File to store 'ansified' file into.
  26.  *                        [default: _input-file.ansi_]
  27.  *
  28.  * Hmm.
  29.  * Add an option to let *word* and _word_ be italicized?
  30.  * 
  31.  * Returns: 0 on success (files open, read, written)
  32.  *         -1 on command-line silliness
  33.  *        1-9 on configuration file parse error
  34.  *         11 on file open error
  35.  *
  36.  * Amy A. Lewis    alewis@email.unc.edu    October, 1995
  37.  */
  38.  
  39. #include <stdlib.h>
  40. #include <stdio.h>
  41. #include <sys/param.h>
  42. #include <unistd.h>
  43. #include <string.h>
  44.  
  45. #define MAXCTL 4               /* length of longest control seq. */
  46.  
  47. FILE    *inp,                   /* input file */
  48.     *outp,                   /* output file */
  49.     *conf;                   /* configuration file */
  50.  
  51. int    remove_codes = 0,           /* remove backspaces anyway (no) */
  52.     verbose = 0;               /* Verbose listings */
  53.  
  54. char    start_under[MAXCTL],           /* strings to hold the control */
  55.     end_under[MAXCTL],           /* sequences to start and end */
  56.     start_bold[MAXCTL],           /* underlining and bold */
  57.     end_bold[MAXCTL],
  58. /*    spec_chars[100][MAXCTL],       / * array of accented characters */
  59.     input_file[MAXPATHLEN],           /* filenames */
  60.     output_file[MAXPATHLEN],
  61.     conf_file[MAXPATHLEN];
  62.  
  63. void usage(char *myname)
  64. {
  65.     fprintf(stderr, "Usage:\n\t%s [-vx] [-c _config-file_] _input-file_ [_output-file_]\n",
  66.         myname);
  67.     fprintf(stderr, "\n\t-v\t\t: Show each transformed string on stderr");
  68.     fprintf(stderr, "\n\t-x\t\t: Strip unknown ^H sequences (like col)");
  69.     fprintf(stderr, "\n\t-c conf-file\t: Use configuration file _conf-file_");
  70.     fprintf(stderr, "\n\tinput-file\t: Name of file to convert");
  71.     fprintf(stderr, "\n\toutput-file\t: Name of converted file\n");
  72.     exit(-1);
  73. }
  74.  
  75. /*
  76.  * getconfig:
  77.  *   Open and read the config file.  Return success/failure
  78.  */
  79. int getconfig(FILE *cf)
  80. {
  81.     int errs, lineno;
  82.     
  83.     errs = lineno = 0;
  84.     if (cf == NULL)                /* No config file, use defaults. */
  85.     {                       /* Ya know, we otter use termcap/info */
  86.     strcpy(start_under, "\033[4m");
  87.     strcpy(end_under, "\033[0m");  /* Is the ESC[24m syntax available? */
  88.     strcpy(start_bold, "\033[1m");
  89.     strcpy(end_bold, "\033[0m");   /* 'Cause this means no bold+ital */
  90. /*    for (lineno = 0; lineno < 100 ; lineno++) spec_chars[lineno][0] = '\0';*/
  91.     }
  92.     /* Read a line, parse it */
  93.     
  94.       /* Barf.  I don't understand whatever that was supposed to be. */
  95. /*        fprintf(stderr, "Parse error in configuration file, line %d discarded.\n", lineno);
  96.         errs++;*/
  97.     return(errs);
  98. }
  99.  
  100. int getargs(int argc, char *argv[])
  101. {
  102.     extern int optind;
  103.     extern char *optarg;
  104.     char ac;
  105.     int pe;
  106.  
  107.     pe = 0;
  108.     while ((ac = getopt(argc, argv, "c:vx")) != EOF)
  109.         switch (ac)
  110.     {
  111.      case 'v':
  112.         verbose = 1;
  113.         break;
  114.      case 'x':               /* act like col(1) */
  115.         remove_codes = 1;
  116.         break;
  117.      case 'c':               /* not currently implemented */
  118.         fprintf(stderr, "Option -c not yet implemented.  Ignored\n");
  119.         strcpy(conf_file, optarg);
  120.         pe = 1;
  121.         break;
  122.      case '?':               /* unknown parameters */
  123.      default:
  124.         usage(argv[0]);
  125.     }
  126.  
  127.     argv += optind;
  128.     
  129.     if (*argv)
  130.     {
  131.         strcpy(input_file, *argv);
  132.         fprintf(stderr, "Input file: %s\n", input_file);
  133.         if (*++argv)               /* output file specified */
  134.             strcpy(output_file, *argv);
  135.     else                   /* ofile not spec., use default */
  136.     {
  137.         strcpy(output_file, input_file);
  138.         strcat(output_file, ".ansi");
  139.     }
  140.     fprintf(stderr, "Output file: %s\n", output_file);
  141.     }
  142.     else
  143.     {
  144.         fprintf(stderr, "No input file name\n");
  145.     usage(argv[0]);
  146.     }
  147.     /* What do we do if some yahoo wants to use the same file for input and
  148.      * output?  A) shit; B) go blind.  No, let's just make a backup and go*/
  149.     if (!strcmp(input_file, output_file))
  150.     {
  151.     fprintf(stderr, "Must use different input/output file names.\n");
  152.     return(17);               /* for the time being, go blind */
  153.     }
  154.     /* open the files */
  155.     if ((inp = fopen(input_file, "r")) == NULL)
  156.     {
  157.         perror(input_file);
  158.         return(11);
  159.     }
  160.     if ((outp = fopen(output_file, "w+")) == NULL)
  161.     {
  162.         perror(output_file);
  163.         return(11);
  164.     }
  165.     if (pe)
  166.         if ((conf = fopen(conf_file, "r")) == NULL)
  167.     {
  168.         perror(conf_file);
  169.         /* return(11);  it isn't implemented yet; 11 when it is?  Or ignore? */
  170.     }
  171.         else
  172.     {
  173.         /* pe = getconfig(conf); Not yet, but this is how we'll do it. */
  174.         pe = getconfig(NULL); /* temporarily */
  175.         /* if (pe) return(pe);  Quit due to parse errors. */
  176.     }
  177.     else getconfig(NULL);
  178.     return(0);
  179. }
  180.  
  181. /*
  182.  * x_string:
  183.  *   Transform a string according the the rules we know.  This will be
  184.  * enhanced muchly much when we have a config file.
  185.  */
  186. void x_string(char *xstr, int trtp)
  187. {
  188.     char holder[BUFSIZ],           /* store as we build */
  189.          *fch, *lch;               /* first and last ^H */
  190.     int i;
  191.     
  192.     /* First, the tests to find out what it is. */
  193.     /* All we know to start with is how long it is, but that can be useful */
  194.     if (strlen(xstr) == 3) /* x^Hy\0 */
  195.     if (xstr[0] == '_')           /* single-letter underline */
  196.     {
  197.         strcpy(holder, start_under);
  198.         strcat(holder, xstr + 2);
  199.         strcat(holder, end_under);
  200.     }
  201.     else if (xstr[0] == xstr[2])   /* single-letter bold.  Odd. */
  202.     {
  203.         strcpy(holder, start_bold);
  204.         strcat(holder, xstr + 2);
  205.         strcat(holder, end_bold);
  206.     }
  207.     else                   /* A single accented character */
  208.     {
  209.         if (remove_codes)
  210.         strcpy(holder, xstr + 2);
  211.         else
  212.             strcpy(holder, xstr);  /* for now.  Later more complex */
  213.     }
  214.     else
  215.         if (trtp == 1)                 /* 'long' underline or bold style */
  216.     {
  217.         fch = strchr(xstr, 0x08);
  218.         lch = strrchr(xstr, 0x08);
  219.         if (strncmp(xstr, lch + 1, strlen(xstr) / 3)) /* long bold */
  220.         {
  221.         strcpy(holder, start_bold);
  222.         strcat(holder, lch + 1);
  223.         strcat(holder, end_bold);
  224.         }
  225.         else if (xstr[0] == '_')   /* assume long underline */
  226.         {
  227.         strcpy(holder, start_under);
  228.         strcat(holder, lch + 1);
  229.         strcat(holder, end_under);
  230.         }
  231.     }
  232.         else if (trtp == 3)           /* 'interleaved' style */
  233.         if (xstr[0] == '_')           /* assume interleaved underline */
  234.         {
  235.         strcpy(holder, start_under);
  236.         for (i = 2; i <= strlen(xstr); i += 3)
  237.         {
  238.             holder[strlen(holder) + 1] = '\0';
  239.             holder[strlen(holder)] = xstr[i];
  240.         }
  241.         strcat(holder, end_under);
  242.         }
  243.         else if (xstr[0] == xstr[2])   /* assume interleaved bold */
  244.         {
  245.         strcpy(holder, start_bold);
  246.         for (i = 2; i <= strlen(xstr); i += 3)
  247.         {
  248.             holder[strlen(holder) + 1] = '\0';
  249.             holder[strlen(holder)] = xstr[i];
  250.         }
  251.         strcat(holder, end_bold);
  252.         }
  253.         else               /* assume multiple spec. chars. */
  254.         if (remove_codes)
  255.             for (i = 2; i <= strlen(xstr); i += 3)
  256.            {
  257.                holder[strlen(holder) + 1] = '\0';
  258.                holder[strlen(holder)] = xstr[i];
  259.            }
  260.         else
  261.             strcpy(holder, xstr);
  262.         else                   /* bloody error, is what */
  263.     {
  264.         if (verbose) fprintf(stderr, "Yuck.  \"%s\".  No change.\n", xstr);
  265.         strcpy(holder, xstr);
  266.     }
  267.     if (verbose) fprintf(stderr, "%s transformed to %s\n", xstr, holder);
  268.     strcpy(xstr, holder);           /* Change the source to pass it back */
  269. }
  270.  
  271.     
  272.     
  273. /*
  274.  * eval_string:
  275.  *   This is where we do all the dirty work.
  276.  * 
  277.  * The parameter line, which is passed in, gets transformed.  No return
  278.  * value, but since multiple words may be highlighted, we check for that
  279.  * and recurse if necessary.  I suspect that this is a nasty little kludge.
  280.  * Yow!  I wish I was a COMPUTER SCIENTIST!
  281.  */
  282. void eval_string(char *line, char *first)
  283. {
  284.     char lastpart[BUFSIZ],           /* Holder for remainder of string */
  285.          word[BUFSIZ],               /* Holder of part to be transformed */
  286.          *next;                   /* a spare pointer */
  287.     int backup,                   /* point at the place to truncate */
  288.         forward,               /* and at end of word */
  289.         tt;                   /* transformation type parameter */
  290.     
  291.     /* Start by finding the boundaries of what's to be transformed */
  292.     /* There are two models:
  293.      * x^Hxy^Hyz^Hz
  294.      * xyz^H^H^Hxyz
  295.      */
  296.     tt = 0;
  297.     backup = forward = 1;
  298.     next = first + 1;
  299.     if (*next == 0x08) 
  300.     {
  301.     while (*next == 0x08)
  302.     {
  303.         backup++;
  304.         forward += 2;
  305.         next++;
  306.     }
  307.     tt = 1;
  308.     }
  309.     else if (next[2] == 0x08)
  310.     {
  311.     tt = 3;
  312.     next = first + 3;
  313.     while (*next == 0x08)
  314.     {
  315.         forward += 3;
  316.         next += 3;
  317.     }
  318.     }                   /* Golly gee whillikers, I hope that works */
  319.     
  320.     /* copy the part in question, and the remainder of the string */
  321.     strncpy(word, first - backup, backup + forward + 1);
  322.     next = first + forward;
  323.     strcpy(lastpart, next);
  324.     
  325.     /* truncate the original string. */
  326.     next = first - backup;
  327.     next[0] = '\0';
  328.     
  329.     x_string(word, tt);
  330.     /* do the transform.  cat the transformed version to the base string */
  331.     strcat(line, word);
  332.     
  333.     /* Okay, here's the tricky part.  Check the remainder of the string
  334.      * If it doesn't have a ctlh, fine.  Cat it onto the base and return.
  335.      * If it does, cat it anyway, reset the first pointer, and recurse */
  336.     if (!(strchr(lastpart, 0x08))) strcat(line,lastpart);
  337.     else
  338.     {
  339.     next = strchr(lastpart, 0x08);
  340.     backup = next - lastpart + strlen(line);      /* offset to ^H */
  341.         first = line + backup;
  342.     strcat(line,lastpart);
  343.     eval_string(line, first);
  344.     }
  345. }
  346.  
  347. int main(int argc, char *argv[])
  348. {
  349.     int ecode;
  350.     char buf[BUFSIZ], *ctlh;
  351.     
  352.     /* read the command line*/
  353.     ecode = getargs(argc,argv);
  354.     if (ecode) return(ecode);           /* This means we die on parse error */
  355. /*  if (ecode > 9) return(ecode);         This wouldn't die for parse errors */
  356.     
  357.     /* Start reading */
  358.     while (!feof(inp))
  359.     {
  360.     fgets(buf, sizeof buf, inp);
  361.     if ((ctlh = strchr(buf, 0x08))) eval_string(buf, ctlh);
  362.     fputs(buf, outp);           /* write it out */
  363.     }
  364.     return(0);
  365. }
  366.